/*
 * Copyright (c) 1994-2019, Joyoung Stock CO.LTD.
 * The IOT Department.
 * All Rights Reserved.
 */

package com.joyoung.sweep.utils.blue;

import android.os.Build;
import android.util.Log;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Locale;

/**
 * Log统一管理类
 */
public class LogUtil {
    private static final String GLOBAL_LOG_TAG = "GlobalDebug";

    private static boolean sDebug = !Build.TYPE.equals("user");
//    private static FileLogger sFileLogger;
    private static final int MAX_LOG_TAG_LENGTH = 23;

//    public static void setFileLogger(FileLogger fileLogger) {
//        sFileLogger = fileLogger;
//    }

    public static void setDebug(boolean debug) {
        sDebug = debug;
//        if (!debug && sFileLogger != null) {
//            sFileLogger.close();
//        }
    }

    public static boolean isDebug() {
        return sDebug;
    }

//    public static String getLogDir() {
//        return sFileLogger == null ? null : sFileLogger.getLogDir();
//    }

    /**
     * Don't use Log.getStackTraceString(), which will hide java.net.UnknownHostException.
     */
    public static String getStackTraceString(Throwable tr) {
        StringWriter sw = new StringWriter(4096);
        PrintWriter pw = new PrintWriter(sw, false);
        tr.printStackTrace(pw);
        pw.flush();
        return sw.toString();
    }

    private static boolean showLog(int level, String tag) {
        return isLoggable(tag, level) || sDebug;
    }

    public static void log(int level, String tag, String msg, Throwable tr, Object... args) {
        if (showLog(level, tag)) {
            if (args != null && args.length > 0) {
                msg = String.format(Locale.US, msg, args);
            }
            logInternal(level, tag, msg, tr);
        }
    }

    private static void logInternal(int level, String tag, String msg, Throwable tr) {
        StringBuilder stringBuilder = new StringBuilder(msg);
        if (tr != null) {
            stringBuilder.append('\n');
            stringBuilder.append(getStackTraceString(tr));
        }
//        if (isShowLineNo) {
//            stringBuilder.append('\n');
//            stringBuilder.append(buildStackTraceElements(Thread.currentThread().getStackTrace()));
//        }
        Log.println(level, tag, stringBuilder.toString());

        logToFile(tag, msg, tr);
    }

    private static boolean isLoggable(String tag, int level) {
        boolean isLoggable = false;
        try {
            isLoggable = Log.isLoggable(tag, level) || Log.isLoggable(GLOBAL_LOG_TAG, level);
        } catch (Exception e) {
            if (sDebug) {
                throw e;
            } else {
                Log.e(tag, "Can't detect is loggable.", e);
            }
        }
        return isLoggable;
    }

    private static void logToFile(String tag, String msg, Throwable tr) {
//        if (sDebug && sFileLogger != null) {
//            sFileLogger.logToFile(tag, msg, tr);
//        }
    }

    // ****************************下面是传入自定义tag及异常的函数*******************************//
    public static void i(String tag, String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.INFO, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.INFO, makeLogTag(tag), msg, tr);
        }
    }

    public static void d(String tag, String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.DEBUG, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.DEBUG, makeLogTag(tag), msg, tr);
        }
    }

    public static void e(String tag, String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.ERROR, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.ERROR, makeLogTag(tag), msg, tr);
        }
    }

    public static void v(String tag, String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.VERBOSE, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.VERBOSE, makeLogTag(tag), msg, tr);
        }
    }

    public static void w(String tag, String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.WARN, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.WARN, makeLogTag(tag), msg, tr);
        }
    }

    // ****************************下面是传入自定义tag及异常的函数*******************************//
    public static void i(String tag, String msg, Throwable tr) {
        log(Log.INFO, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void d(String tag, String msg, Throwable tr) {
        log(Log.DEBUG, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void e(String tag, String msg, Throwable tr) {
        log(Log.ERROR, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void v(String tag, String msg, Throwable tr) {
        log(Log.VERBOSE, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void w(String tag, String msg, Throwable tr) {
        log(Log.WARN, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    // *********************************下面四个是默认tag的函数**********************************//
    public static void i(String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.INFO, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.INFO, GLOBAL_LOG_TAG, msg, null);
        }
    }

    public static void d(String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.DEBUG, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.DEBUG, GLOBAL_LOG_TAG, msg, null);
        }
    }

    public static void e(String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.ERROR, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.ERROR, GLOBAL_LOG_TAG, msg, null);
        }
    }

    public static void v(String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.VERBOSE, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.VERBOSE, GLOBAL_LOG_TAG, msg, null);
        }
    }

    public static void w(String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.WARN, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.WARN, GLOBAL_LOG_TAG, msg, null);
        }
    }

    // *********************************下面四个是默认tag的函数**********************************//
    public static void i(String msg) {
        log(Log.INFO, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void d(String msg) {
        log(Log.DEBUG, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void e(String msg) {
        log(Log.ERROR, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void v(String msg) {
        log(Log.VERBOSE, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void w(String msg) {
        log(Log.WARN, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    // *********************************下面是传入异常的函数*************************************//
    public static void i(String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.INFO, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.INFO, GLOBAL_LOG_TAG, msg, tr);
        }
    }

    public static void d(String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.DEBUG, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.DEBUG, GLOBAL_LOG_TAG, msg, tr);
        }
    }

    public static void e(String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.ERROR, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.ERROR, GLOBAL_LOG_TAG, msg, tr);
        }
    }

    public static void v(String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.VERBOSE, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.VERBOSE, GLOBAL_LOG_TAG, msg, tr);
        }
    }

    public static void w(String msg, Throwable tr, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.WARN, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
        } else {
            log(Log.WARN, GLOBAL_LOG_TAG, msg, tr);
        }
    }

    // *********************************下面是传入异常的函数*************************************//
    public static void i(String msg, Throwable tr) {
        log(Log.INFO, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void d(String msg, Throwable tr) {
        log(Log.DEBUG, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void e(String msg, Throwable tr) {
        log(Log.ERROR, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void v(String msg, Throwable tr) {
        log(Log.VERBOSE, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    public static void w(String msg, Throwable tr) {
        log(Log.WARN, GLOBAL_LOG_TAG, msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), tr);
    }

    // *********************************下面是传入自定义tag的函数********************************//
    public static void i(String tag, String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.INFO, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.INFO, makeLogTag(tag), msg, null);
        }
    }

    public static void d(String tag, String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.DEBUG, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.DEBUG, makeLogTag(tag), msg, null);
        }
    }

    public static void e(String tag, String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.ERROR, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.ERROR, makeLogTag(tag), msg, null);
        }
    }

    public static void v(String tag, String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.VERBOSE, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.VERBOSE, makeLogTag(tag), msg, null);
        }
    }

    public static void w(String tag, String msg, boolean isShowLineNo) {
        if (isShowLineNo) {
            log(Log.WARN, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
        } else {
            log(Log.WARN, makeLogTag(tag), msg, null);
        }
    }

    // *********************************下面是传入自定义tag的函数********************************//
    public static void i(String tag, String msg) {
        log(Log.INFO, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void d(String tag, String msg) {
        log(Log.DEBUG, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void e(String tag, String msg) {
        log(Log.ERROR, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void v(String tag, String msg) {
        log(Log.VERBOSE, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }

    public static void w(String tag, String msg) {
        log(Log.WARN, makeLogTag(tag), msg + buildStackTraceElements(Thread.currentThread().getStackTrace()), null);
    }


    // *************************************************
    public static void i(String tag, String msgFormat, Object... args) {
        log(Log.INFO, makeLogTag(tag), msgFormat + buildStackTraceElements(Thread.currentThread().getStackTrace()), null, args);
    }

    /**
     * Record logs using String#format()
     */
    public static void d(String tag, String msgFormat, Object... args) {
        log(Log.DEBUG, makeLogTag(tag), msgFormat + buildStackTraceElements(Thread.currentThread().getStackTrace()), null, args);
    }

    public static void e(String tag, String msgFormat, Object... args) {
        log(Log.ERROR, makeLogTag(tag), msgFormat + buildStackTraceElements(Thread.currentThread().getStackTrace()), null, args);
    }

    public static void v(String tag, String msgFormat, Object... args) {
        log(Log.VERBOSE, makeLogTag(tag), msgFormat + buildStackTraceElements(Thread.currentThread().getStackTrace()), null, args);
    }

    public static void w(String tag, String msgFormat, Object... args) {
        log(Log.WARN, makeLogTag(tag), msgFormat + buildStackTraceElements(Thread.currentThread().getStackTrace()), null, args);
    }


    // ******************************************************************************************//

    /**
     * 过滤过长TAG
     *
     * @param str 原始TAG
     */
    public static String makeLogTag(String str) {
        if (str.length() > MAX_LOG_TAG_LENGTH) {
            return str.substring(0, MAX_LOG_TAG_LENGTH - 1);
        }
        return str;
    }

    /**
     * 获取当前代码所在类、方法、行数
     *
     * @return 返回当前线程栈信息
     */
    private static String buildStackTraceElements(StackTraceElement[] elements) {
        StringBuilder sb = new StringBuilder();
        sb.append("  \t===> ");
        if (elements.length < 4) {
            Log.e(GLOBAL_LOG_TAG, "Stack to shallow");
        } else {
            String fullClassName = elements[3].getClassName();
            sb.append(fullClassName.substring(fullClassName.lastIndexOf(".") + 1)).append(".").append(elements[3].getMethodName()).append("(...)").append(" [line ").append(elements[3].getLineNumber()).append("]");
        }
        return sb.toString();
    }

//    private static String getClassName(StackTraceElement[] elements) {
//        if (elements.length < 4) {
//            Log.e(GLOBAL_LOG_TAG, "Stack to shallow");
//            return GLOBAL_LOG_TAG;
//        } else {
//            String fullClassName = elements[3].getClassName();
//            return fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
//        }
//    }


}